package com.sino.androiddesign.anim

import android.animation.*
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import com.sino.androiddesign.R
import com.sino.androiddesign.anim.objanimator2.ColorEvaluator
import kotlinx.android.synthetic.main.activity_property.*


/**
 * 属性动画 :
 * 参考地址:https://www.jianshu.com/p/2412d00a0ce4
 *
 *
 * 2 简介:
 *    2.1: 作用对象 : 任意Java对象,不再局限于视图View对象
 *    2.2: 动画效果: 可自定义各种动画效果
 *    不再局限于平移,旋转,缩放,透明度这四种动画
 * 4 工作原理:
 *     在一定时间间隔内,通过不断对值进行改变,并不断将该值赋给对象的属性,
 *     从而实现对象在该属性上的动画效果
 *   最重要的两个类:valueAnimator和ObjectAnimator
 *
 * 5  具体使用
 *    5.1 valueAnimator
 *      定义:属性动画机制中最核心的一个类
 *      实现动画的原理;通过不断控制值得变化,再不断手动赋值给对象的属性,从而实现动画效果
 *      valueAnimator类中3个重要的方法:
 *       1:ValueAnimator.ofInt(int values);
 *       2:ValueAnimator.ofFloat(float values);
 *       3:ValueAnimator.ofObject(int values);
 *       5.1.1: ValueAnimator.ofInt(int values)
 *        作用:将初始值以整形数值的形式过渡到结束值
 *        即估值器是整形估值器 -IntEvaluator
 *    5.2 ObjectAnimator 类
 *    直接对对象的属性值进行改变操作,从而实现动画效果 ,继承于ValueAnimator
 *     5.2.1 具体使用
 *     平移、旋转、缩放 & 透明度
 *     ObjectAnimator.ofFloat(object,"alpha",float...values)
 *
 *   5.3 两者的区别
 *     valueAnimator 先改变值 然后手动赋值给对象的属性从而实现动画,是间接对对象属性进行操作
 *     ObjectAnimator 先改变值 然后自动赋值给对象的属性从而实现动画,是直接对对象属性进行操作
 *
 */
class PropertyActivity : AppCompatActivity() {
    private val TAG: String = "PropertyActivity"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_property)

        initOfInt()

        initTestValueAnimator()

        initObjectAnimator()

        initTestObjectAnimator()
        otherAnimator()
    }

    private fun initTestValueAnimator() {
        test_btn.setOnClickListener {
            val animator = ValueAnimator.ofInt(test_btn.width, test_btn.width + 500)
            animator.duration = 2000
            animator.addUpdateListener { animation ->
                val animatedValue = animation.animatedValue as Int
                test_btn.width = animatedValue
                test_btn.requestLayout()
            }
            animator.start()
        }
    }

    /**
     * 5.1.1 ValueAnimator.ofInt(int values)(ofFloat与ofInt类似)
     */
    private fun initOfInt() {
        ofInt_java_btn.setOnClickListener {
            //创建一个动画实例,
            // ofInt(a,b...) 将多个int参数进行平滑过渡,a->b->...
            val anim: ValueAnimator = ValueAnimator.ofInt(0, 10, 50, 200)
            anim.duration = 2000
            anim.startDelay = 0
            //ValueAnimator.INFINITE 无限重放
            anim.repeatCount = 0
            anim.repeatMode = ValueAnimator.RESTART
            anim.addUpdateListener { animation ->
                //每改变一次就调用一次
                val currentValue: Int = animation!!.animatedValue as Int
                Log.e(TAG, "更新值 => $currentValue")
                //重新绘制 ui
                ofInt_iv.layout(currentValue, ofInt_iv.top, ofInt_iv.width + currentValue, ofInt_iv.bottom)
            }
            anim.start()

        }

        ofInt_xml_btn.setOnClickListener {
            val animator = AnimatorInflater.loadAnimator(this@PropertyActivity, R.animator.set_animation) as ValueAnimator


            animator.addUpdateListener { animation ->
                val currentValue = animation!!.animatedValue as Int
                ofInt_iv.layout(currentValue, ofInt_iv.top, ofInt_iv.width + currentValue, ofInt_iv.bottom)
            }
            animator.start()
        }
    }

    /**
     * 5.1.3 ValueAnimator.ofObject(int values)
     * // 创建初始动画时的对象  & 结束动画时的对象
     *  myObject object1 = new myObject();
     *  myObject object2 = new myObject();
     *  ValueAnimator anim = ValueAnimator.ofObject(new myObjectEvaluator(), object1, object2);
     *  // 创建动画对象 & 设置参数
     *  // 参数说明
     *  // 参数1：自定义的估值器对象（TypeEvaluator 类型参数） - 下面会详细介绍
     *  // 参数2：初始动画的对象
     *  // 参数3：结束动画的对象
     *  anim.setDuration(5000);
     *  anim.start();
     *
     *  估值器(TypeEvaluator) 介绍
     *   作用: 设置动画如何从初始值过渡到结束值得判断
     *   1: 插值器(interpolator) 决定值得变化模式(匀速,加速等等)
     *   2: 估值器(TypeEvaluator) 决定值得具体变化数值
     *
     *   fFloat 内部都实现了一个FloatEvaluator插值器
     *   FloatEvaluator 可以参考
     *
     *    ValueAniamtor.ofObject()需要自定义估值器 来告诉系统如何从出事对象过渡
     *   结束对象的逻辑,操作对象 其实就是操作对象中所包含的具体的数值
     *
     *   参考 objectAnimator包下 的创建方式
     */


    /**
     *ObjectAnimator 继承于ValueAnimator所有许多属性都是通用的
     */
    private fun initObjectAnimator() {
        obj_java_btn.setOnClickListener {
            val objectAnimator = ObjectAnimator.ofFloat(obj_iv, View.ALPHA, 0f, 1f)
            objectAnimator.duration = 3000
            objectAnimator.start()

        }

        obj_xml_btn.setOnClickListener {

            val loadAnimator = AnimatorInflater.loadAnimator(this, R.animator.obj_animator)
            loadAnimator.setTarget(obj_iv)
            loadAnimator.start()

        }

    }

    /**
     * 5.2.3 通过自定义对象属性实现动画效果
     *   对于属性动画,其拓展性在于:不局限于系统限定的动画,可以自定义动画,即自定义对象的属性,
     *   并通过操作自定义的属性进而实现动画
     *
     *   1: 为对象设置需要操作的属性set() & get()方法 必须有的
     *   2: 通过实现TypeEvaluator类从而定义属性变化的逻辑
     *  参考 com.sino.androiddesign.anim.objanimator2.MuView2
     */

    private fun initTestObjectAnimator() {
        val animator = ObjectAnimator.ofObject(test_view2!!, "color", ColorEvaluator(),
                "#0000FF", "#FF0000")
        animator.duration = 4000
        animator.start()
    }


    /**
     * 6 动画的组合使用
     *
     *  AnimatorSet.play(Animator anim)   ：播放当前动画
     *  AnimatorSet.after(long delay)   ：将现有动画延迟x毫秒后执行
     *  AnimatorSet.with(Animator anim)   ：将现有动画和传入的动画同时执行
     *  AnimatorSet.after(Animator anim)   ：将现有动画插入到传入的动画之后执行
     *  AnimatorSet.before(Animator anim) ：  将现有动画插入到传入的动画之前执行
     */


    private fun setJavaObjectAnimator() {
        // 步骤1：设置需要组合的动画效果
        val translation = ObjectAnimator.ofFloat(test_btn, View.TRANSLATION_X, 0f, 300f, 0f)
        // 平移动画
        val rotate = ObjectAnimator.ofFloat(test_btn, View.ROTATION, 0f, 360f)
        // 旋转动画
        val alpha = ObjectAnimator.ofFloat(test_btn, View.ALPHA, 1f, 0f, 1f)
        // 透明度动画

        // 步骤2：创建组合动画的对象
        val animSet = AnimatorSet()

        // 步骤3：根据需求组合动画
        animSet.play(translation).with(rotate).before(alpha)
        animSet.duration = 5000

        // 步骤4：启动动画
        animSet.start()
    }

    private fun setXmlObjectAnimator() {
        val animatorSet = AnimatorInflater.loadAnimator(this, R.animator.obj_set_animator) as AnimatorSet
        animatorSet.setTarget(test_btn)
        animatorSet.start()
    }


    /**
     * 动画的另外一种使用方式
     *  // 特别注意:
    // 动画自动启动,无需调用start()方法.因为新的接口中使用了隐式启动动画的功能，只要我们将动画定义完成后，动画就会自动启动
    // 该机制对于组合动画也同样有效，只要不断地连缀新的方法，那么动画就不会立刻执行，等到所有在ViewPropertyAnimator上设置的方法都执行完毕后，动画就会自动启动
    // 如果不想使用这一默认机制，也可以显式地调用start()方法来启动动画
     */

    private fun otherAnimator(){
        test_btn.animate()
                .translationX(400f)
                .setDuration(4000)
                .setListener(object : AnimatorListenerAdapter(){
                    override fun onAnimationStart(animation: Animator?) {
                        super.onAnimationStart(animation)
                        //可以只写一个想要监听的时刻
                    }
                })

    }
}
